package xyz.xtt.schedule.service;

import java.math.BigInteger;
import java.util.Arrays;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.web3j.protocol.core.methods.response.EthBlock;

import com.tongtong.middleware.vo.response.EstimateGasRes;
import com.tongtong.middleware.vo.response.TransactionMergeData;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.schedule.entity.ChainTransactionEntity;

/**
 * @author wangqi
 */
@RefreshScope
@Service
@Slf4j
public class SyncBlockService {
	public final int startNumber = 11314718;

	@Value("${bsn.contract.addr}")
	private String address;
	@Autowired
	InnerService innerService;
	@Autowired
	StringRedisTemplate stringRedisTemplate;
	@Autowired
	ChainTransactionService chainTransactionService;

	public void executeTask() {
		String[] addresses = address.split(",");
		while (true) {
			// 查询当前处理的区块高度
			String syncBlockNumber = stringRedisTemplate.opsForValue().get("SCHEDULED:SYNCHRONIZE_BLOCK_NUMBER");
			if (syncBlockNumber == null) {
				stringRedisTemplate.opsForValue().set("SCHEDULED:SYNCHRONIZE_BLOCK_NUMBER", String.valueOf(startNumber));
				continue;
			}
			// 查询当前区块高度
			int sbn = Integer.parseInt(syncBlockNumber);
			// 如果redis记录小于程序配置，则使用程序配置
			if (startNumber > sbn) {
				stringRedisTemplate.opsForValue().set("SCHEDULED:SYNCHRONIZE_BLOCK_NUMBER", String.valueOf(startNumber));
				continue;
			}
			BigInteger blockNumber = innerService.getBlockNumber();
			// 逐一分析区块里的交易
			System.out.println("从" + sbn + "开始遍历区块");
			if (blockNumber.intValue() - sbn < 3) {
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					throw new RuntimeException(e);
				}
			}
			int end = Math.min(sbn + 10, blockNumber.intValue());
			for (int i = sbn; i <= end; i++) {
				EthBlock.Block ethBlock = innerService.getBlockByNumber(BigInteger.valueOf(i));
				stringRedisTemplate.opsForValue().set("SCHEDULED:SYNCHRONIZE_BLOCK_NUMBER", String.valueOf(i));
				// 分析交易内容
				if (!ethBlock.getTransactions().isEmpty()) {
					for (EthBlock.TransactionResult transactionResult : ethBlock.getTransactions()) {
						EthBlock.TransactionObject transaction = (EthBlock.TransactionObject) transactionResult.get();
						// 对to进行匹配
						if (transaction.getTo() == null) {
							continue;
						}
						int index = Arrays.binarySearch(addresses, transaction.getTo());
						// 如果匹配到
						if (index >= 0) {
							System.out.println(JSONUtil.toJsonStr(transaction));
							TransactionMergeData transactionMergeData = innerService.getTransactionInfo(transaction.getHash());
							String errorMsg;
							if ("0x1".equals(transactionMergeData.getStatus())) {
								errorMsg = "";
							} else {
								EstimateGasRes estimateGasRes = innerService
										.estimateGas(transactionMergeData.getFrom(), transactionMergeData.getTo(), transactionMergeData.getInput());
								errorMsg = estimateGasRes.getMsg();
							}
							// 分析input判断交易类型
							String input10 = transactionMergeData.getInput().substring(0, 10);
							String method = getType(input10);
							// 插入数据库
							boolean ok = chainTransactionService
									.addTransaction(new ChainTransactionEntity(
											transactionMergeData.getHash(), transactionMergeData.getFrom(), transactionMergeData.getTo(),
											transactionMergeData.getBlockNumber().toString(), ethBlock.getTimestamp().intValue(),
											transactionMergeData.getGasUsed().toString(), transactionMergeData.getStatus().substring(2), errorMsg, method));
							if (ok) {
								log.info("QueryBlock 交易插入成功:{}", transaction.getHash());
							}
						}
					}
				}
			}
		}
	}

	public static String getType(String method) {
		return switch (method) {
		case "0x156e29f6" -> "mint1155";
		case "0xd81d0a15" -> "mintBatch1155";
		case "0xf5298aca" -> "burn1155";
		case "0x6b20c454" -> "burnBatch1155";
		case "0xf242432a" -> "transfer1155";
		case "0x2eb2c2d6" -> "transferBatch1155";
		case "0x9430b496" -> "approval";
		case "0x40c10f19" -> "mint721";
		case "0x42966c68" -> "burn721";
		case "0x42842e0e" -> "transfer721";
		default -> "unknown";
		};
	}
}
